// -*- mode: c++; indent-tabs-mode: nil; -*-
//
//The Biomolecule Toolkit (BTK) is a C++ library for use in the
//modeling, analysis, and design of biological macromolecules.
//Copyright (C) 2006, Tim Robertson <kid50@users.sourceforge.net>
//
//This program is free software; you can redistribute it and/or modify
//it under the terms of the GNU Lesser General Public License as published
//by the Free Software Foundation; either version 2.1 of the License, or (at
//your option) any later version.
//
//This program is distributed in the hope that it will be useful,  but
//WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public License
//along with this program; if not, write to the Free Software Foundation,
//Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

#include <vector>
#include <list>
#include <algorithm>

#include <boost/iterator/reverse_iterator.hpp>

#include <btk/core/utility/grouped_element_iterator.hpp>

#include "test_common.hpp"

using namespace std;
using BTK::UTILITY::GroupedElementIterator;

typedef vector<int> group_type;
typedef list<group_type> list_type;
typedef GroupedElementIterator<list_type::iterator,
                               group_type::iterator,
                               group_type,
                               int> iterator_type;

typedef boost::reverse_iterator<iterator_type> reverse_iterator_type;

void fill_group_list(unsigned group_size,
                     unsigned num_groups,
                     list_type & glist)
{
  glist.clear();
  unsigned element = 0;

  for (unsigned g = 0; g < num_groups; ++g) {
    glist.push_back(group_type());
    group_type & cur_group = glist.back();

    for (unsigned i = 0; i < group_size; ++i) {
      cur_group.push_back(element++);
    }
  }
}

int main() {
  list_type test_list;
  fill_group_list(5,4,test_list);
  iterator_type i, end, copy;

  i = iterator_type(test_list.begin(),
                    test_list.end());
  end = iterator_type(test_list.begin(),
                      test_list.end(),
                      true);

  //
  // test basic equality/inequality
  //
  BOOST_TEST(i == i);
  BOOST_TEST(end == end);
  BOOST_TEST(i != end);

  copy = i;

  BOOST_TEST(i == copy);
  BOOST_TEST(i != ++copy);
  BOOST_TEST(i == --copy);

  //
  // test forward/reverse iteration with forward iterators
  //
  test_iteration(i,end,20,true);

  //
  // test reverse iterator equality/inequality
  //
  reverse_iterator_type ri,rend,rcopy;
  ri = reverse_iterator_type(iterator_type(test_list.begin(),
                                           test_list.end(),
                                           true));

  rend = reverse_iterator_type(iterator_type(test_list.begin(),
                                             test_list.end()));

  BOOST_TEST(ri != rend);
  BOOST_TEST(ri == ri);
  BOOST_TEST(rend == rend);

  rcopy = ri;

  BOOST_TEST(ri == rcopy);
  BOOST_TEST(ri != ++rcopy);
  BOOST_TEST(ri == --rcopy);

  test_iteration(ri,rend,20,true);
  
  //
  // test iteration over empty groups
  //
  test_list.push_front(group_type());
  test_list.push_back(group_type());

  i = iterator_type(test_list.begin(),
                    test_list.end());
  end = iterator_type(test_list.begin(),
                      test_list.end(),
                      true);

  test_iteration(i,end,20,true);

  //
  // test corner case -- iteration of list of empty groups
  //
  list_type empty_list;
  fill_group_list(0,5,empty_list);

  i = iterator_type(empty_list.begin(),
                    empty_list.end());
  end = iterator_type(empty_list.begin(),
                      empty_list.end(),
                      true);

  test_iteration(i,end,0,true);

  return boost::report_errors();
}
